<?php
/**
 * 框架 - 访问控制类
 * 
 * @version $Id: AccessControll.php 187 2011-05-23 07:57:55Z linsir123 $
 */
class AccessControll
{
	/**
	 * @var 访问控制列表
	 */
	public $accessRules;
	
	/**
	 * @var 待验证的控制器方法名称
	 */
	public $actionName;
	
	/**
	 * @var 角色 // 0,表示游客；非0,表示登录用户
	 */
	public $user;
	
	/**
	 * @var 是否允许执行
	 */
	public $canRun = true;
	
	/**
	 * 构造函数
	 * 
	 * 根据当然的Session取角色信息
	 */
	public function __construct()
	{
		@session_start();
		$key = App::instance()->userSessionKey;
		$this->user = isset($_SESSION[$key]);
	}
	
	/**
	 * 检查某个控制器
	 * 
	 * array(
	 *		'actions' => array(), // 省略表示全部的控制器方法都限制
	 *		'users' => array() // *,表示任意角色；@,表示登录后的角色
	 *	)
	 */
	public function check($accessRules, $actionName)
	{
		if (empty($accessRules) || !is_array($accessRules)) 
			return true;
		
		///
		$this->actionName = $actionName;
		$this->accessRules = $accessRules;
		foreach ($this->accessRules as $type => $rules) {
			if (in_array($type, array('allow', 'deny'))) 
				$this->canRun = call_user_func_array(array($this, '_'.$type), 
					array($rules));
		}
		
		return $this->canRun;
	}
	
	/**
	 * 验证允许操作
	 * 
	 * 默认允许访问，
	 * 有指定方法列表，而当前方法又不在列表中时，则不允许访问
	 * 有指定方法列表并且当前在列表中，则需要根据角色判断允许访问
	 * 
	 * 任意角色，或当前角色在角色列表中，或需要登录并且当前角色已登录，则允许访问
	 */
	private function _allow($rules = null)
	{
		$canRun = true;
		if ($actions = $rules['actions']) {
			if (!in_array($this->actionName, $actions)) 
				$canRun = false;
		}
		
		$users = $rules['users'];
		if ($canRun) 
			$canRun = in_array('*', $users) || in_array($this->user, $users, true) || (in_array('@', $users) && $this->user);
		
		return $canRun;
	}
	
	/**
	 * 验证拒绝操作
	 * 
	 * 默认允许访问，
	 * 有指定方法列表，而当前方法又在不列表中时，则允许访问
	 * 没有指定方法列表，或有指定方法列表并且当前在列表中，则需要根据角色判断允许访问
	 * 
	 * 任意角色，或当前角色在角色列表中，或需要登录并且当前角色已登录，则不允许访问
	 */
	private function _deny($rules = null)
	{
		$canRun = true;
		if ($actions = $rules['actions']) {
			if (in_array($this->actionName, $actions)) 
				$canRun = false;
		}
		
		$users = $rules['users'];
		if (empty($actions) || !$canRun) 
			$canRun = !(in_array('*', $users) || in_array($this->user, $users, true) || (in_array('@', $users) && $this->user));
			
		return $canRun;
	}
}
